#ifndef __VISITOR_H__
#define __VISITOR_H__
#include<iostream>
#include<string>
#include<list>

class Visitor;

class Medicine{
public:
    virtual ~Medicine(){}
    virtual float getPrice() = 0;
    virtual std::string getName() = 0;
    virtual void accept(Visitor* vistor) = 0;
};

class StomachMed : public Medicine{
public:
    virtual float getPrice(){
        return 40.3f;
    }
    virtual std::string getName(){
        return "stomache medicine";
    }
    virtual void accept(Visitor* vistor);
};

class ColdMed : public Medicine{
public:
    virtual float getPrice(){
        return 20.3f;
    }
    virtual std::string getName(){
        return "cold medicine";
    }
    virtual void accept(Visitor* vistor);
};

class AntiInflammatoryMed : public Medicine{
public:
    virtual float getPrice(){
        return 30.3f;
    }
    virtual std::string getName(){
        return "anti inflammatory medicine";
    }
    virtual void accept(Visitor* vistor);
};

class Visitor{
public:
    ~Visitor(){}
    virtual void visitStomachMdc(StomachMed* stomac_mdc) =0;
    virtual void visitColdMdc(ColdMed* stomac_mdc) =0;
    virtual void visitAntiInflammatoryMdc(AntiInflammatoryMed* stomac_mdc) =0;
};

class SfVisitor : public Visitor{
public:
    virtual void visitStomachMdc(StomachMed* stomac_mdc);
    virtual void visitColdMdc(ColdMed* stomac_mdc);
    virtual void visitAntiInflammatoryMdc(AntiInflammatoryMed* stomac_mdc);
    void showTotalPrice() const{
        std::cout <<  m_totalPrice << std::endl;
    }

private:
    float m_totalPrice;
};


class QyVisitor : public Visitor{
public:
    virtual void visitStomachMdc(StomachMed* stomac_mdc);
    virtual void visitColdMdc(ColdMed* stomac_mdc);
    virtual void visitAntiInflammatoryMdc(AntiInflammatoryMed* stomac_mdc);

private:
    float m_totalPrice;
};

class ObjectStructure{
public:
    ~ObjectStructure(){
        for(auto it = m_medicines.begin();it!=m_medicines.end();it++)
        {
            delete *it;
        }
        m_medicines.clear();
    }
    void addMedicine(Medicine* medicine){
        m_medicines.push_back(medicine);
    }
    void ProcAction(Visitor* visitor){
         for(auto it = m_medicines.begin();it!=m_medicines.end();it++)
        {
            (*it)->accept(visitor);
        }
    }

private:
    std::list<Medicine*> m_medicines;

};

#endif